home *** CD-ROM | disk | FTP | other *** search
/ Hardcore Visual Basic 5.0 (2nd Edition) / Hardcore Visual Basic 5.0 - Second Edition (1997)(Microsoft Press).iso / Code / EXECUT~1.CLS < prev    next >
Text File  |  1997-06-14  |  13KB  |  474 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4. END
  5. Attribute VB_Name = "CExecutive"
  6. Attribute VB_GlobalNameSpace = False
  7. Attribute VB_Creatable = True
  8. Attribute VB_PredeclaredId = False
  9. Attribute VB_Exposed = True
  10. Option Explicit
  11.  
  12. Public Enum EWaitMode
  13.     ewmWaitIdle = -1
  14.     ewmNoWait
  15.     ewmWaitDead
  16. End Enum
  17.  
  18. Public Enum EErrorExecutive
  19.     eeBaseExecutive = 13060     ' CExecutive
  20. End Enum
  21.  
  22. Private proc As PROCESS_INFORMATION
  23. Private Start As STARTUPINFO
  24. Private sInitDir As String
  25. Private sProg As String
  26. Private iExit As Long
  27. Private ewm As EWaitMode
  28. Private sPipedInText As String, hReadStdIn As Long, hWriteStdIn As Long
  29. Private sPipedOutText As String, hReadStdOut As Long, hWriteStdOut As Long
  30. Private sPipedErrText As String, hReadStdErr As Long, hWriteStdErr As Long
  31.  
  32. Private Sub Class_Initialize()
  33.     Reset
  34. End Sub
  35.  
  36. Private Sub Class_Terminate()
  37.     CloseAll
  38. End Sub
  39.  
  40. Private Sub CloseAll()
  41.     CloseHandleNull hReadStdIn
  42.     CloseHandleNull hWriteStdIn
  43.     CloseHandleNull hReadStdOut
  44.     CloseHandleNull hReadStdErr
  45. End Sub
  46.  
  47. Sub Reset()
  48.     With Start
  49.         .cb = LenB(Start)
  50.         .dwFlags = 0
  51.         .lpTitle = sNullStr
  52.         .dwX = -1
  53.         .dwY = -1
  54.         .dwXSize = -1
  55.         .dwYSize = -1
  56.         .dwFillAttribute = -1
  57.         .dwXCountChars = -1
  58.         .dwYCountChars = -1
  59.         .wShowWindow = -1
  60.     End With
  61.     With proc
  62.         .dwProcessId = 0
  63.         .dwThreadId = 0
  64.         .hProcess = 0
  65.         .hThread = 0
  66.     End With
  67.     sInitDir = sNullStr
  68.     iExit = -1
  69.     ewm = ewmNoWait
  70.     CloseAll
  71. End Sub
  72.  
  73. Property Get WaitMode() As EWaitMode
  74.     WaitMode = ewm
  75. End Property
  76.  
  77. Property Let WaitMode(ByVal ewmA As EWaitMode)
  78.     Select Case ewmA
  79.     Case ewmWaitDead, ewmWaitIdle
  80.         ewm = ewmA
  81.     Case Else ' Unrecognized same as ewmNoWait
  82.         ewm = ewmNoWait
  83.     End Select
  84. End Property
  85.  
  86. Property Get ProcessID() As Long
  87.     ProcessID = proc.dwProcessId
  88. End Property
  89.  
  90. Property Get ThreadID() As Long
  91.     ThreadID = proc.dwThreadId
  92. End Property
  93.  
  94. Property Get ExitCode() As Long
  95.     If ewm <> ewmNoWait Then
  96.         ' If a WaitMode was on, we already have the exit code
  97.         ExitCode = iExit
  98.     Else
  99.         ' Otherwise open a handle and get exit code
  100.         Dim hProcess As Long
  101.         hProcess = OpenProcess(PROCESS_SET_INFORMATION, False, _
  102.                                proc.dwProcessId)
  103.         GetExitCodeProcess hProcess, ExitCode
  104.     End If
  105. End Property
  106.  
  107. Property Get Completed() As Boolean
  108.     Completed = (ExitCode <> STILL_ACTIVE)
  109. End Property
  110.  
  111. Property Get Show() As VbAppWinStyle
  112.     Show = Start.wShowWindow
  113. End Property
  114.  
  115. Property Let Show(eswShow As VbAppWinStyle)
  116. With Start
  117.     .wShowWindow = eswShow
  118.     If eswShow = -1 Then
  119.         .dwFlags = .dwFlags And (Not STARTF_USESHOWWINDOW)
  120.     Else
  121.         .dwFlags = .dwFlags Or STARTF_USESHOWWINDOW
  122.     End If
  123. End With
  124. End Property
  125.  
  126. Property Get Title() As String
  127.     If UnicodeTypeLib Then
  128.         Title = Start.lpTitle
  129.     Else
  130.         Title = StrConv(Start.lpTitle, vbUnicode)
  131.     End If
  132. End Property
  133.  
  134. Property Let Title(sTitle As String)
  135.     If UnicodeTypeLib Then
  136.         Start.lpTitle = sTitle
  137.     Else
  138.         Start.lpTitle = StrConv(sTitle, vbFromUnicode)
  139.     End If
  140. End Property
  141.  
  142. Property Get InitDir() As String
  143.     InitDir = sInitDir
  144. End Property
  145.  
  146. Property Let InitDir(sInitDirA As String)
  147.     If MUtility.ExistFileDir(sInitDirA) Then sInitDir = sInitDirA
  148. End Property
  149.  
  150. Property Get Left() As Long
  151.     Left = Start.dwX
  152. End Property
  153.  
  154. Property Let Left(ByVal xLeft As Long)
  155. With Start
  156.     .dwX = xLeft
  157.     If .dwX = -1 Then
  158.         .dwY = -1
  159.         .dwFlags = .dwFlags And (Not STARTF_USEPOSITION)
  160.     Else
  161.         .dwFlags = .dwFlags Or STARTF_USEPOSITION
  162.     End If
  163. End With
  164. End Property
  165.  
  166. Property Get Top() As Long
  167.     Top = Start.dwY
  168. End Property
  169.  
  170. Property Let Top(ByVal yTop As Long)
  171. With Start
  172.     .dwY = yTop
  173.     If .dwX = -1 Then
  174.         .dwY = -1
  175.         .dwFlags = .dwFlags And (Not STARTF_USEPOSITION)
  176.     Else
  177.         .dwFlags = .dwFlags Or STARTF_USEPOSITION
  178.     End If
  179. End With
  180. End Property
  181.  
  182. Property Get Width() As Long
  183.     Width = Start.dwXSize
  184. End Property
  185.  
  186. Property Let Width(ByVal xWidth As Long)
  187. With Start
  188.     .dwXSize = xWidth
  189.     If .dwXSize = -1 Then
  190.         .dwYSize = -1
  191.         .dwFlags = .dwFlags And (Not STARTF_USESIZE)
  192.     Else
  193.         .dwFlags = .dwFlags Or STARTF_USESIZE
  194.     End If
  195. End With
  196. End Property
  197.  
  198. Property Get Height() As Long
  199.     Height = Start.dwYSize
  200. End Property
  201.  
  202. Property Let Height(ByVal yHeight As Long)
  203. With Start
  204.     .dwYSize = yHeight
  205.     If .dwYSize = -1 Then
  206.         .dwXSize = -1
  207.         .dwFlags = .dwFlags And (Not STARTF_USESIZE)
  208.     Else
  209.         .dwFlags = .dwFlags Or STARTF_USESIZE
  210.     End If
  211. End With
  212. End Property
  213.  
  214. Property Get Columns() As Long
  215.     Columns = Start.dwXCountChars
  216. End Property
  217.  
  218. Property Let Columns(ByVal xColumns As Long)
  219. With Start
  220.     .dwXCountChars = xColumns
  221.     If .dwXCountChars = -1 Then
  222.         .dwYCountChars = -1
  223.         .dwFlags = .dwFlags And (Not STARTF_USECOUNTCHARS)
  224.     Else
  225.         .dwFlags = .dwFlags Or STARTF_USECOUNTCHARS
  226.     End If
  227. End With
  228. End Property
  229.  
  230. Property Get Rows() As Long
  231.     Rows = Start.dwYCountChars
  232. End Property
  233.  
  234. Property Let Rows(ByVal yRows As Long)
  235. With Start
  236.     .dwYCountChars = yRows
  237.     If .dwYCountChars = -1 Then
  238.         .dwXCountChars = -1
  239.         .dwFlags = .dwFlags And (Not STARTF_USECOUNTCHARS)
  240.     Else
  241.         .dwFlags = .dwFlags Or STARTF_USECOUNTCHARS
  242.     End If
  243. End With
  244. End Property
  245.  
  246. Property Get BackColor() As Long
  247.     BackColor = MBytes.LoByte(Start.dwFillAttribute)
  248. End Property
  249.  
  250. Property Let BackColor(ByVal atrBackColor As Long)
  251. With Start
  252.     If atrBackColor = -1 Then
  253.         .dwFillAttribute = -1
  254.         .dwFlags = .dwFlags And (Not STARTF_USEFILLATTRIBUTE)
  255.     Else
  256.         atrBackColor = MBytes.LShiftWord(atrBackColor, 4)
  257.         .dwFillAttribute = .dwFillAttribute And &HF Or atrBackColor
  258.         .dwFlags = .dwFlags Or STARTF_USEFILLATTRIBUTE
  259.     End If
  260. End With
  261. End Property
  262.  
  263. Property Get ForeColor() As Long
  264.     ForeColor = MBytes.HiByte(MBytes.LoWord(Start.dwFillAttribute))
  265. End Property
  266.  
  267. Property Let ForeColor(ByVal atrForeColor As Long)
  268. With Start
  269.     If atrForeColor = -1 Then
  270.         .dwFillAttribute = -1
  271.         .dwFlags = .dwFlags And (Not STARTF_USEFILLATTRIBUTE)
  272.     Else
  273.         .dwFillAttribute = .dwFillAttribute And &HF0 Or atrForeColor
  274.         .dwFlags = .dwFlags Or STARTF_USEFILLATTRIBUTE
  275.     End If
  276. End With
  277. End Property
  278.  
  279. Property Get FullScreen() As Boolean
  280.     FullScreen = Start.dwFlags And STARTF_RUNFULLSCREEN
  281. End Property
  282.  
  283. Property Let FullScreen(fFullScreen As Boolean)
  284. With Start
  285.     If fFullScreen Then
  286.         .dwFlags = .dwFlags Or STARTF_RUNFULLSCREEN
  287.     Else
  288.         .dwFlags = .dwFlags And (Not STARTF_RUNFULLSCREEN)
  289.     End If
  290. End With
  291. End Property
  292.  
  293. Property Get IsWindowed() As Boolean
  294.     Dim ept As EProgramType
  295.     ept = MExeType.ExeType(ProgPath)
  296.     IsWindowed = ept <> eptMSDOS And ept <> eptWin32Console And _
  297.                  ept <> eptDOSUnknown And ept <> eptOS2_1
  298. End Property
  299.  
  300. Property Get ProgName() As String
  301.     ProgName = MUtility.GetFileBaseExt(MUtility.SearchForExe(sProg))
  302. End Property
  303.  
  304. Property Get ProgPath() As String
  305.     ProgPath = MUtility.GetFullPath(MUtility.SearchForExe(sProg))
  306. End Property
  307.  
  308. Property Get PipedInText() As String
  309.     PipedInText = sPipedInText
  310. End Property
  311.  
  312. Property Let PipedInText(sPipedInTextA As String)
  313.     sPipedInText = sPipedInTextA
  314.     ' Close any open handles
  315.     CloseHandleNull hReadStdIn
  316.     CloseHandleNull hWriteStdIn
  317. End Property
  318.  
  319. Property Get PipedOutText() As String
  320.     PipedOutText = sPipedOutText
  321. End Property
  322.  
  323. Property Get PipedErrText() As String
  324.     PipedErrText = sPipedErrText
  325. End Property
  326.  
  327. Sub Run(sCmd As String)
  328.  
  329.     ' Process any environment variables
  330.     Dim sCmdLine As String, sPipeOut As String, sPipeErr As String
  331.     sCmdLine = MUtility.ExpandEnvStr(sCmd)
  332.     sProg = MParse.GetQToken(sCmdLine, " ")
  333.     
  334.     ' Create standard input, output, and error pipes
  335.     CreatePipes
  336.     
  337.     ' Create process and run it
  338.     If CreateProcess(sNullStr, sCmdLine, ByVal pNull, ByVal pNull, _
  339.                      APITRUE, 0&, pNull, sInitDir, Start, proc) Then
  340.         
  341.         ' Must close write end of out and err handles before you can read
  342.         CloseHandleNull hWriteStdOut
  343.         CloseHandleNull hWriteStdErr
  344.         
  345.         Select Case ewm
  346.         Case ewmWaitIdle
  347.             ' Wait, but allow painting and other processing
  348.             Do
  349.                 GetExitCodeProcess proc.hProcess, iExit
  350.                 DoEvents
  351.             Loop Until ReadPipeChunk And ReadPipeErrChunk And Completed
  352.         Case ewmWaitDead
  353.             ' Stop dead until process terminates
  354.             Dim iResult As Long
  355.             iResult = WaitForSingleObject(proc.hProcess, INFINITE)
  356.             If iResult = WAIT_FAILED Then ErrRaise Err.LastDllError
  357.             ' Get the return value
  358.             GetExitCodeProcess proc.hProcess, iExit
  359.             Do
  360.             Loop Until ReadPipeChunk And ReadPipeErrChunk And Completed
  361.         Case Else
  362.             ' Caller must call use ExitCode and pipe chunks directly
  363.         End Select
  364.         CloseHandleNull proc.hProcess
  365.         CloseHandleNull proc.hThread
  366.     Else
  367.         ApiRaise Err.LastDllError
  368.     End If
  369. End Sub
  370. '
  371.  
  372. Private Sub CloseHandleNull(h As Long)
  373.     If h <> hNull Then CloseHandle h
  374.     h = hNull
  375. End Sub
  376.  
  377. Sub CreatePipes()
  378. With Start
  379.     Dim saPipe As SECURITY_ATTRIBUTES, f As Long, c As Long
  380.     saPipe.nLength = LenB(saPipe)
  381.     saPipe.bInheritHandle = APITRUE
  382.     saPipe.lpSecurityDescriptor = pNull
  383.     .dwFlags = .dwFlags Or STARTF_USESTDHANDLES
  384.     ' Create anonymous pipe for standard output
  385.     f = CreatePipe(hReadStdOut, hWriteStdOut, saPipe, 0)
  386.     If f = False Then ApiRaise Err.LastDllError
  387.     .hStdOutput = hWriteStdOut
  388.     ' Create anonymous pipe for standard error
  389.     f = CreatePipe(hReadStdErr, hWriteStdErr, saPipe, 0)
  390.     If f = False Then ApiRaise Err.LastDllError
  391.     .hStdError = hWriteStdErr
  392.     If sPipedInText = sEmpty Then
  393.         .hStdInput = hNull
  394.     Else
  395.         ' Create anonymous pipe for standard input
  396.         f = CreatePipe(hReadStdIn, hWriteStdIn, saPipe, 0)
  397.         If f = False Then ApiRaise Err.LastDllError
  398.         .hStdInput = hReadStdIn
  399.         ' Write input string to handle
  400.         Dim abPipedInText() As Byte
  401.         MBytes.StrToBytes abPipedInText, sPipedInText
  402.         f = WriteFile(hWriteStdIn, abPipedInText(0), _
  403.                       MBytes.LenBytes(abPipedInText), c, ByVal pNull)
  404.         If f = False Then ApiRaise Err.LastDllError
  405.         CloseHandleNull hWriteStdIn
  406.     End If
  407. End With
  408. End Sub
  409.  
  410. Function ReadPipeChunk(Optional sChunk As String, _
  411.                        Optional ByVal cWant As Long = 512) As Boolean
  412.     Dim f As Long, cGot As Long, cPeek As Long, fDone As Boolean, abChunk() As Byte
  413.     ' See if program is done
  414.     fDone = Completed
  415.     ' See if there's more in the pipe
  416.     f = PeekNamedPipe(hReadStdOut, pNull, 0, 0, cPeek, 0)
  417.     If (f <> 0) And (cPeek <> 0) Then
  418.         ' Read a chunk of bytes
  419.         ReDim abChunk(0 To cWant - 1)
  420.         Call ReadFile(hReadStdOut, abChunk(0), cWant, cGot, ByVal pNull)
  421.         sChunk = MBytes.LeftBytes(abChunk, cGot)
  422.         sPipedOutText = sPipedOutText & sChunk
  423.     End If
  424.     ' Strange difference between WinNT and Win95
  425.     If MUtility.IsNT Then
  426.         If (cGot = 0) And fDone Then ReadPipeChunk = True
  427.     Else
  428.         If (cPeek = 0) And fDone Then ReadPipeChunk = True
  429.     End If
  430. End Function
  431.  
  432. Function ReadPipeErrChunk(Optional sChunk As String, _
  433.                           Optional ByVal cWant As Long = 512) As Boolean
  434.     Dim f As Long, cGot As Long, cPeek As Long, fDone As Boolean, abChunk() As Byte
  435.     ' See if program is done
  436.     fDone = Completed
  437.     ' See if there's more in the pipe
  438.     f = PeekNamedPipe(hReadStdErr, pNull, 0, 0, cPeek, 0)
  439.     If (f <> 0) And (cPeek <> 0) Then
  440.         ' Read a chunk of bytes
  441.         ReDim abChunk(0 To cWant - 1)
  442.         Call ReadFile(hReadStdErr, abChunk(0), cWant, cGot, ByVal pNull)
  443.         sChunk = MBytes.LeftBytes(abChunk, cGot)
  444.         sPipedErrText = sPipedErrText & sChunk
  445.     End If
  446.     ' Strange difference between WinNT and Win95
  447.     If MUtility.IsNT Then
  448.         If (cGot = 0) And fDone Then ReadPipeErrChunk = True
  449.     Else
  450.         If (cPeek = 0) And fDone Then ReadPipeErrChunk = True
  451.     End If
  452. End Function
  453.  
  454. #If fComponent = 0 Then
  455. Private Sub ErrRaise(e As Long)
  456.     Dim sText As String, sSource As String
  457.     If e > 1000 Then
  458.         sSource = App.ExeName & ".Executive"
  459.         Select Case e
  460.         Case eeBaseExecutive
  461.             BugAssert True
  462.        ' Case ee...
  463.        '     Add additional errors
  464.         End Select
  465.         Err.Raise COMError(e), sSource, sText
  466.     Else
  467.         ' Raise standard Visual Basic error
  468.         sSource = App.ExeName & ".VBError"
  469.         Err.Raise e, sSource
  470.     End If
  471. End Sub
  472. #End If
  473.  
  474.